Skip to content

Fix bugs, add DeepSeek LLM support, and implement Custom Framework Builder (v1.2)#2

Open
PanwalaVandan wants to merge 10 commits intoMikeDominic92:masterfrom
PanwalaVandan:fix/deepseek-integration-and-bug-fixes
Open

Fix bugs, add DeepSeek LLM support, and implement Custom Framework Builder (v1.2)#2
PanwalaVandan wants to merge 10 commits intoMikeDominic92:masterfrom
PanwalaVandan:fix/deepseek-integration-and-bug-fixes

Conversation

@PanwalaVandan
Copy link
Copy Markdown

@PanwalaVandan PanwalaVandan commented Mar 14, 2026

Summary

Bug Fixes

  • Datetime timezone mismatch — Fixed TypeError in risk scoring when comparing naive vs timezone-aware datetimes (_calculate_document_freshness_score)
  • Analysis page blank screen — Backend returns snake_case fields (finding_type, confidence_score, etc.) but frontend expected camelCase; added normalizeFinding() mapper and FindingsErrorBoundary
  • Document upload timeout — Placeholder API key strings were fooling the is_configured() check, causing silent 30s timeouts
  • Documents not linking to vendor — Upload page was not passing vendor_id from URL params to the POST request
  • "View All Findings" showing nothing — Navigation to /analysis had no document context; now passes ?document_id= param
  • Login/dashboard redirect loop — Stale Zustand persisted isAuthenticated: true caused infinite redirects; fixed in authStore.ts, api.ts (clear on 401), and App.tsx (init delay)
  • Registration 422 error — Backend password validation rejecting weak passwords silently; added frontend strength validation
  • Risk page 500 — Naive datetime in SQLite vs timezone-aware datetime.now(timezone.utc) comparison crash

New Feature: DeepSeek LLM Provider

  • Added DeepSeekService using the OpenAI-compatible endpoint (https://api.deepseek.com)
  • Extended config.py with deepseek_api_key, deepseek_model, deepseek_base_url settings
  • Updated create_llm_service() factory to support provider = "deepseek"

New Feature: Custom Framework Builder (v1.2 Feature 1)

  • Backend: New CustomFramework and CustomControl SQLAlchemy models with full cascade delete
  • Backend: Full CRUD API under /api/v1/custom-frameworks (create, list, get, update, delete frameworks and controls)
  • Backend: Analysis engine updated to accept custom_framework_id; builds prompt from custom controls and tags findings as custom:<name>
  • Frontend: New /frameworks page — list view with cards, edit view with controls table, inline add/edit control form
  • Frontend: Clone from Built-in — 2-step modal fetching all real built-in frameworks and controls from the API, with search and per-control checkboxes for selective import
  • Frontend: Analysis page extended to load and select custom frameworks from a dropdown

Test Plan

  • Register a new account and log in
  • Upload a vendor document and verify it appears under the correct vendor
  • Run analysis using DeepSeek — confirm findings appear without blank screen
  • Open Risk page — confirm no 500 error
  • Navigate to Custom Frameworks, create a framework, add controls manually
  • Use Clone from Built-in — verify all frameworks load, search filters work, selected controls import correctly
  • Run analysis using a custom framework — confirm findings are tagged with the custom framework name

Adds DeepSeek-V3/R1 as a third LLM provider option alongside Anthropic
and Gemini. DeepSeek uses an OpenAI-compatible API so no new dependencies
are required.

- backend/app/config.py: added deepseek_api_key, deepseek_model,
  deepseek_base_url settings; updated llm_provider comment
- backend/app/services/llm.py: added DeepSeekService class implementing
  all five LLM methods (analyze_document, analyze_document_with_prompt,
  generate_finding_details, answer_query, _generate); updated
  create_llm_service() factory to handle LLM_PROVIDER=deepseek
SQLite stores datetimes without timezone info (naive), but the code used
datetime.now(timezone.utc) (aware). Subtracting them raised:

  TypeError: can't subtract offset-naive and offset-aware datetimes

Fix: treat naive datetimes from SQLite as UTC before comparison in
_calculate_document_freshness_score().
The backend FindingResponse uses snake_case (confidence_score,
framework_control, finding_type, remediation, created_at) while the
frontend Finding type and all its consuming components (FindingCard,
FindingsList) expected camelCase. This caused a crash on render because
finding.findingType was undefined and .charAt(0) threw a TypeError,
resulting in a completely blank Analysis page.

Changes:
- frontend/src/lib/findings.ts: new normalizeFinding() utility that maps
  every backend field to its camelCase counterpart; splits framework_control
  into controlId and controlName; defaults missing fields safely
- frontend/src/pages/Analysis.tsx: apply normalizeFinding() to API response;
  add FindingsErrorBoundary to catch any future render crashes; read
  ?document_id= URL param to allow vendor/document pages to pre-select a
  document; increase analysis timeout to 180s for LLM calls
…dor page

When navigating to /documents?vendor_id=<id> (e.g. from the vendor detail
page), the upload form now passes vendor_id as a query parameter to the
POST /api/v1/documents endpoint. Previously the parameter was ignored and
documents appeared under Others with no vendor link.

Also increases the upload request timeout to 120s to accommodate large files
and slow document processing.
The View All Findings button previously navigated to /analysis with no
context, leaving the page empty. It now navigates to
/analysis?document_id=<first_analyzed_doc_id> so the document is
pre-selected and existing findings are loaded immediately.

Also applies normalizeFinding() to vendor-level findings so the severity
breakdown sidebar renders correctly.
When the backend was restarted or tokens expired, Zustand's persisted store
could retain isAuthenticated: true while localStorage had no tokens. On the
next page load, ProtectedRoute saw isAuthenticated: true and redirected to
/dashboard, which immediately redirected back to /login, creating a loop.

Three-part fix:
- authStore.ts: init() now explicitly resets user/tokens/isAuthenticated
  to null/false when no tokens are found in localStorage, clearing any
  stale persisted state
- api.ts: 401 response handler also clears the auth-storage Zustand persist
  key so the store resets on the next load after token expiry
- App.tsx: defers route rendering until after init() completes via a ready
  flag, preventing ProtectedRoute/PublicRoute from reading stale Zustand
  state before the reset has run
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 14, 2026

Deploy Preview for vendor-audit-ai failed. Why did it fail? →

Name Link
🔨 Latest commit eccfe54
🔍 Latest deploy log https://app.netlify.com/projects/vendor-audit-ai/deploys/69c40f7dc448f400087ee420

Add full custom compliance framework CRUD and wire it into the
analysis pipeline so users can define their own controls and run
AI analysis against them exactly like built-in frameworks.

Backend:
- New CustomFramework + CustomControl SQLAlchemy models
- New Pydantic schemas (create/update/response/list)
- New /custom-frameworks REST endpoints (framework + control CRUD)
- Register models in __init__.py, router under /custom-frameworks
- Extend AnalysisRequest with optional custom_framework_id field
- analysis.py service: fetch custom framework + inject controls
  into LLM prompt; store framework as "custom:<name>" on run
- analysis.py endpoint: validate exactly one of framework /
  custom_framework_id is supplied

Frontend:
- New Frameworks page: list view, edit view, controls table,
  add/edit control inline form, clone-from-built-in modal,
  Run Analysis shortcut button
- Export Frameworks from pages/index.ts
- Add /frameworks route in App.tsx
- Add Frameworks nav link (Layers icon) in Sidebar.tsx
- Analysis page: fetch /custom-frameworks, show as second
  optgroup in framework dropdown, pass custom_framework_id
  in POST body when a custom framework is selected,
  support ?custom_framework_id= URL param for deep-linking
…mport

Clone modal now fetches real frameworks from GET /api/v1/frameworks and
loads all controls via GET /api/v1/frameworks/{id}/controls. Added a
2-step flow: pick framework, then select controls from a searchable
checkbox list with Select All / Clear shown options. Imports all
selected controls including description, category and guidance fields.
@PanwalaVandan PanwalaVandan changed the title FEAT/FIX: DeepSeek LLM provider + 5 bug fixes Fix bugs, add DeepSeek LLM support, and implement Custom Framework Builder (v1.2) Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant